package com.nf;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;


/**
 * 　　* @description: TODO
 * 　　* @param
 * 　　* @return
 * 　　* @throws
 * 　　* @author Administrator
 * 　　* @date $ $
 *
 */

public class MiniBeanProcessor{

    public <T> T newInstance(Class<T> c) throws SQLException {
        T newInstance = null;
        try {
            newInstance = c.newInstance();
        } catch (InstantiationException e) {
            throw new SQLException(
                    "Cannot create " + c.getName() + ": " + e.getMessage());
        } catch (IllegalAccessException e) {
            throw new SQLException(
                    "Cannot create " + c.getName() + ": " + e.getMessage());
        }
        return newInstance;
    }

    public PropertyDescriptor[] propertyDescriptors(Class<?> c) throws SQLException {
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(c);
        } catch (IntrospectionException e) {
            throw new SQLException("获取bean信息失败");
        }
        return beanInfo.getPropertyDescriptors();
    }

    private String getColumnName(ResultSetMetaData rsmd, int i) throws SQLException {
        String columnName = rsmd.getColumnLabel(i);
        if (columnName == null || columnName.length() == 0) {
            columnName = rsmd.getColumnName(i);
        }
        return columnName;
    }

    protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException {
        int cols = rsmd.getColumnCount();
        int[] columnToProperty = new int[cols + 1];
        Arrays.fill(columnToProperty, Constants.PROPERTY_NOT_FOUND);
        for (int i = 1; i <= cols; i++) {
            String columnName = getColumnName(rsmd, i);
            for (int j = 0; j < props.length; j++) {
                PropertyDescriptor descriptor = props[j];
                if (columnName.equals(descriptor.getName())) {
                    columnToProperty[i] = j;
                    break;
                }
            }
        }
        return columnToProperty;
    }

    private void callSetter(Object bean, PropertyDescriptor prop, Object value) throws SQLException {
        Method writeMethod = prop.getWriteMethod();
        try {
            writeMethod.invoke(bean, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private <T> T populateBean(ResultSet rs, T bean, PropertyDescriptor[] props, int[] columnToProperty)
            throws SQLException {
        for (int i = 1; i < columnToProperty.length; i++) {
            int propPos = columnToProperty[i];
            if (propPos == Constants.PROPERTY_NOT_FOUND) {
                continue;
            }
            PropertyDescriptor descriptor = props[propPos];
            Object value = rs.getObject(i);
            callSetter(bean,descriptor,value);
        }
        return  bean;
    }


    public <T> T populateBean(ResultSet rs, T bean) throws SQLException {
        PropertyDescriptor[] props = this.propertyDescriptors(bean.getClass());
        ResultSetMetaData rsmd = rs.getMetaData();
        int[] columnToProperty = mapColumnsToProperties(rsmd, props);
        return populateBean(rs, bean, props, columnToProperty);
    }

    public <T> T toBean(ResultSet rs, Class<? extends T> type) throws SQLException {
        T bean = newInstance(type);
        return populateBean(rs, bean);
    }
}
